package com.example.shiro;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.sys.entity.Menu;
import com.example.sys.entity.Role;
import com.example.sys.entity.User;
import com.example.sys.service.MenuService;
import com.example.sys.service.RoleService;
import com.example.sys.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

//    @Autowired
//    private PermissionService permissionService;

    @Autowired
    private MenuService menuService;

    @Autowired
    private RoleService roleService;


    /**
     * 获取用户角色和权限，用于权限认证
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String loginName = principals.getPrimaryPrincipal().toString();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        User user = userService.findUserByUserName(loginName);
        Set<String> roles = new HashSet<String>();
        Set<String> menus = new HashSet<String>();
        List<Menu> menuList = new ArrayList<>();
        List<Role> roleList = new ArrayList<>();

        //获取角色(从数据库中取出时使用逗号分隔的)
//        进行判断，如果是管理员，则赋予全部权限
        if (user.getUserName().equals("admin")) {
            roleList = roleService.list();
            for (Role role : roleList) {
                roles.add(role.getRoleKey());
            }
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.isNotNull("perms");
            queryWrapper.ne("perms","");
            menuList = menuService.list(queryWrapper);
            for (Menu menu : menuList) {
                menus.add(menu.getPerms());
            }
        } else {
            roleList = roleService.findRoleByUserId(user.getUserId());
            for (Role role : roleList) {
                roles.add(role.getRoleKey());
            }
            menuList = menuService.findMenuByUserId(user.getUserId());
            for (Menu menu : menuList) {
                menus.add(menu.getPerms());
            }
        }
        info.setRoles(roles);
        info.setStringPermissions(menus);
        return info;
    }

    /**
     * 设置用户登录认证
     * @param
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //UsernamePasswordToken对象用来存放提交的登录信息
        UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
        //实际项目中，这里可以根据实际情况做缓存，如果不做，Shiro自己也是有时间间隔机制，2分钟内不会重复执行该方法
        User user = userService.findUserByUserName(token.getUsername());

        //用户是否存在
        if(user==null){
            throw new UnknownAccountException();
        }
//        //是否激活
//        if(user!=null&&user.getStatus().equals(ConstantsUser.ZERO.getCode())){
//            throw new  DisabledAccountException();
//        }
        //是否锁定
//        if(user!=null&&user.getStatus().equals(ConstantsUser.THREE.getCode())){
//            throw new  LockedAccountException();
//        }
        //若存在，将此用户存放到登录认证info中，无需自己做密码对比Shiro会为我们进行密码对比校验
//        if(user!=null&&user.getStatus().equals(ConstantsUser.ONE.getCode())) {
//这里盐值可以自定义
        if(user!=null) {
//            ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername()+user.getSalt());
            ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUserName()+user.getSalt());
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    user.getUserName(), //用户名
                    user.getPassword(), //密码
                    credentialsSalt,//salt=loginName+salt
                    getName()  //realm name
            );
            return authenticationInfo;
        }
        return null;
    }

}